package com.yuanss.backenddemo.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yuanss.backenddemo.common.R;
import com.yuanss.backenddemo.constant.SysUserConstant;
import com.yuanss.backenddemo.dao.SysUserDao;
import com.yuanss.backenddemo.dao.SysUserRoleDao;
import com.yuanss.backenddemo.entity.dto.LogInResultDto;
import com.yuanss.backenddemo.entity.dto.LoginDto;
import com.yuanss.backenddemo.entity.po.SysUser;
import com.yuanss.backenddemo.entity.po.SysUserRole;
import com.yuanss.backenddemo.entity.vo.req.AddUserReqVo;
import com.yuanss.backenddemo.entity.vo.req.QueryUserReqVo;
import com.yuanss.backenddemo.entity.vo.req.UpdateUserReqVo;
import com.yuanss.backenddemo.entity.vo.rsp.QueryUserDetailRspVo;
import com.yuanss.backenddemo.service.SysUserService;
import com.yuanss.backenddemo.utils.MD5Utils;
import com.yuanss.backenddemo.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author yuanss
 * @version 1.0
 * @description 系统用户服务实现层
 * @date 2024/6/8 22:20:00
 */
@Slf4j
@Service
public class SysUserServiceImpl implements SysUserService {

    @Resource
    private SysUserDao sysUserDao;

    @Resource
    private SysUserRoleDao sysUserRoleDao;

    @Resource
    private RedisUtils redisUtils;

    private static final String LOCK_PREFIX = "login:attempts:";
    private static final int MAX_ATTEMPTS = 5; // 最大尝试次数
    private static final int LOCK_DURATION = 10; // 锁定时间（分钟）

    /**
     * 添加用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R addUser(AddUserReqVo addUserReqVo) {
        // 添加用户信息
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(addUserReqVo,sysUser);
        // 默认状态
        sysUser.setStatus(SysUserConstant.status.NORMAL);
        sysUser.setDelFlag(SysUserConstant.delFlag.NORMAL);
        sysUser.setCreateBy(SysUserConstant.ADMIN_ID);
        sysUser.setCreateTime(new Date());
        // 处理密码
        dealPassword(sysUser);
        sysUserDao.insert(sysUser);
        // 添加用户-角色信息
        List<SysUserRole> sysUserRoles = getSysUserRoles(addUserReqVo, sysUser);
        if(sysUserRoles.isEmpty()){
            return R.success("添加成功");
        }
        sysUserRoleDao.insertBatch(sysUserRoles);
        return R.success("添加成功");
    }

    /**
     * 处理密码
     * @param sysUser
     */
    private void dealPassword(SysUser sysUser) {
        // 默认密码
        if(sysUser.getPassword() == null){
            sysUser.setPassword(SysUserConstant.DEFAULT_PASSWORD);
        }
        // 密码加密
        sysUser.setPassword(MD5Utils.md5(sysUser.getPassword()));
    }

    /**
     * 获取用户角色信息
     * @param addUserReqVo   添加用户请求参数
     * @param sysUser        用户信息对象
     * @return               用户角色信息
     */
    private static List<SysUserRole> getSysUserRoles(AddUserReqVo addUserReqVo, SysUser sysUser) {
        List<SysUserRole> sysUserRoles = new ArrayList<>();
        Arrays.stream(addUserReqVo.getRoleIds()).forEach(roleId -> {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(sysUser.getUserId());
            sysUserRole.setRoleId(roleId);
            sysUserRoles.add(sysUserRole);
        });
        return sysUserRoles;
    }

    /**
     * 删除用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R deleteUser(Long userIds) {
        // 删除用户信息
        sysUserDao.deleteById(userIds);
        // 删除用户-角色信息
        sysUserRoleDao.deleteByUserId(userIds);
        return R.success("删除成功");
    }

    /**
     * 更新用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R updateUser(UpdateUserReqVo updateUserReqVo) {
        // 更新用户信息
        SysUser sysUser = sysUserDao.queryById(updateUserReqVo.getUserId());
        if(sysUser == null){
            return R.error("用户不存在");
        }
        BeanUtils.copyProperties(updateUserReqVo,sysUser);
        sysUser.setUpdateTime(new Date());
        sysUser.setUpdateBy(SysUserConstant.ADMIN_ID);
        // 处理密码
        dealPassword(sysUser);
        sysUserDao.update(sysUser);
        // 更新用户-角色信息
        // 先删除旧数据
        sysUserRoleDao.deleteByUserId(updateUserReqVo.getUserId());
        // 添加新数据
        List<SysUserRole> sysUserRoles = getSysUserRoles(updateUserReqVo, sysUser);
        if(sysUserRoles.isEmpty()){
            return R.success("修改成功");
        }
        sysUserRoleDao.insertBatch(sysUserRoles);
        return R.success("修改成功");
    }

    /**
     * 查询用户详情
     */
    @Override
    public R<QueryUserDetailRspVo> queryUser(Long userId) {
        QueryUserDetailRspVo queryUserDetailRspVo = sysUserDao.queryDetailById(userId);
        if(queryUserDetailRspVo == null){
            return R.error("用户不存在");
        }
        List<Long> roleIds = sysUserRoleDao.queryRoleIdByUserId(userId);
        queryUserDetailRspVo.setRoleIds(roleIds);
        return R.success(queryUserDetailRspVo);
    }

    /**
     * 查询所有用户
     */
    @Override
    public R<List<SysUser>> queryAllUser(QueryUserReqVo queryUserReqVo) {
        // 开启分页
        PageHelper.startPage(queryUserReqVo.getPageNum(),queryUserReqVo.getPageSize());
        // 查询
        List<SysUser> sysUsers = sysUserDao.queryAllByLimit(queryUserReqVo);
        // 封装分页信息
        PageInfo<SysUser> pageInfo = PageInfo.of(sysUsers);
        // 返回
        return R.success(pageInfo.getTotal(),sysUsers);
    }

    /**
     * 改变用户状态
     */
    @Override
    public R changeStatus(Long userId) {
        SysUser sysUser = sysUserDao.queryById(userId);
        if(sysUser == null){
            return R.error("用户不存在");
        }
        // 状态转换
        if(SysUserConstant.status.NORMAL.equals(sysUser.getStatus())){
            sysUser.setStatus(SysUserConstant.status.DISABLE);
        }else{
            sysUser.setStatus(SysUserConstant.status.NORMAL);
        }
        sysUser.setUpdateTime(new Date());
        sysUser.setUpdateBy(SysUserConstant.ADMIN_ID);
        sysUserDao.update(sysUser);
        return R.success("用户状态已修改");
    }

    /**
     * 校验用户名是否唯一
     */
    @Override
    public boolean checkUserNameUnique(UpdateUserReqVo updateUserReqVo) {
        SysUser sysUser = sysUserDao.selectByUserName(updateUserReqVo.getUserName());
        return checkInfo(updateUserReqVo, sysUser);
    }

    /**
     * 校验查询结果
     * @param updateUserReqVo
     * @param sysUser
     * @return
     */
    private static boolean checkInfo(UpdateUserReqVo updateUserReqVo, SysUser sysUser) {
        // 未查询到用户信息
        if(sysUser == null){
            return true;
        }
        // 查询到用户信息，判断是否是同一个用户
        return sysUser.getUserId().equals(updateUserReqVo.getUserId());
    }

    /**
     * 校验手机号是否唯一
     */
    @Override
    public boolean checkPhoneUnique(UpdateUserReqVo updateUserReqVo) {
        SysUser sysUser = sysUserDao.selectByPhone(updateUserReqVo.getUserName());
        // 未查询到用户信息
        return checkInfo(updateUserReqVo, sysUser);
    }

    /**
     * 校验邮箱是否唯一
     */
    @Override
    public boolean checkEmailUnique(UpdateUserReqVo updateUserReqVo) {
        SysUser sysUser = sysUserDao.selectByEmail(updateUserReqVo.getUserName());
        // 未查询到用户信息
        return checkInfo(updateUserReqVo, sysUser);
    }

    @Override
    public LogInResultDto verify(LoginDto loginDto) {
        // 锁定校验
        if (isLocked(loginDto.getUsername())){
            return LogInResultDto.builder().result(false).msg("账号已被锁定").build();
        }
        Map<String, Object> result = new HashMap<>();
        SysUser sysUser = sysUserDao.selectByUserName(loginDto.getUsername());
        String msg = "用户名或密码错误";
        // 用户校验
        if(ObjectUtils.isEmpty(sysUser)){
            log.error("用户不存在");
            // 添加错误次数
            recordLoginErrorCount(loginDto.getUsername());
            return LogInResultDto.builder().result(false).msg(msg).build();
        }
        // 状态校验
        if(sysUser.getStatus().equals(SysUserConstant.status.DISABLE)){
            log.error("用户已禁用");
            return LogInResultDto.builder().result(false).msg("用户已禁用").build();
        }
        // 密码校验
        String password = MD5Utils.md5(sysUser.getPassword());
        if(password.equals(loginDto.getPassword())){
            log.error("密码错误");
            // 添加错误次数
            return LogInResultDto.builder().result(false).msg(msg).build();
        }
        return LogInResultDto.builder().result(true).msg("验证通过").build();
    }

    /**
     * 登录失败次数校验
     * @param username  用户名
     * @return          true: 锁定
     */
    private boolean isLocked(String username) {
        // 登录失败次数校验,采用redis
        String key = LOCK_PREFIX + username;
        if(redisUtils.hasKey(key)){
            // 获取失败次数
            Object res = redisUtils.get(key);
            int errCount = ObjectUtils.isEmpty(res)?0:Integer.parseInt(res.toString());
            //
            if(errCount >= MAX_ATTEMPTS){
                log.error("账号已被锁定");
                return true;
            }
        }
        return false;
    }

    /**
     * 记录登录失败次数
     * @param username  用户名
     */
    private void recordLoginErrorCount(String username) {
        String key = LOCK_PREFIX + username;
        Long attempts = redisUtils.increment(key, 1);
        if(attempts == 1){
            // 第一次登录失败，设置过期时间
            redisUtils.expire(key, LOCK_DURATION, TimeUnit.MINUTES);
        }
    }
}
